package edu.neumont.csc380.esp.service;

import java.security.interfaces.RSAKey;
import java.util.Random;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.util.DigestUtils;

import edu.neumont.csc380.esp.api.EspionageService;
import edu.neumont.csc380.esp.entities.Key;
import edu.neumont.csc380.esp.entities.RSA_Key;
import edu.neumont.csc380.prime.service.PrimeClientServerAPI;
import edu.neumont.csc380.prime.service.ProbablePrime;
import edu.neumont.csc380.prime.service.ProbablyPrimeService;

import java.security.MessageDigest;
/**
 * EspionageServiceImp uses InYourPrime to generate an RSA Key consisting
 * of a public key and a private key
 * @author jdaniel
 *
 */
@WebService
public class EspionageServiceImp implements EspionageService{

	private PrimeClientServerAPI primeClientServerAPI = JAXRSClientFactory.create("http://localhost:8080/InYourPrime/rest", PrimeClientServerAPI.class);
	
	@WebMethod
	/**
	 * generateKey gets two large prime numbers from InYourPrime and uses them to generate a public and private key
	 */
	public RSA_Key generateKey(@WebParam(name = "identifier") String identifier) {
		ProbablePrime pp = primeClientServerAPI.getProbablePrimeXML();
		while(pp.getConfidence() < .99){
			pp = primeClientServerAPI.getProbablePrimeXML(pp.getNumber(), pp.getWitnesses().toString());
		}
		
	
		int p = pp.getNumber();
		
		pp = primeClientServerAPI.getProbablePrimeXML();
		while(pp.getConfidence() < .99){
			pp = primeClientServerAPI.getProbablePrimeXML(pp.getNumber(), pp.getWitnesses().toString());
		}
		
		int q = pp.getNumber();
		
		long n = p*q;
		long phi = (p-1)*(q-1);
		
		Random rand = new Random();
		long e;
		do{
			e = rand.nextLong()+1;
		}while(e > phi || gcd(e,phi) !=1);
		
		long d = extended_gcd(e,phi);
		
		RSA_Key key = new RSA_Key(new Key(n,e),new Key(n,d));
		return key;
	}
	
	private static long gcd(long a, long b){
		if(b == 0) return a;
		else return gcd(b,a%b);
	}
	
	private static long extended_gcd(long a, long b){
		long x = 0, lastY = 0;
		long y = 1 , lastX = 1;
		
		while(b!=0){
			long quotient = a/b;
			long temp = a;
			a = b;
			b = temp % b;

			temp = x;
			x = lastX-quotient*x;
			lastX = temp;
			
			temp = y;
			y = lastY-quotient*y;
			lastY = temp;
		}
		
		return lastX;
	}
}
